using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;
using Engine;
using GameEntitySystem;

namespace Game
{
	public class PlayerSlave
	{
		private class ListenedInventory : IInventory
		{
			private IInventoryListener listener;

			[CompilerGenerated]
			private IInventory _003COriginal_003Ek__BackingField;

			public IInventory Original
			{
				[CompilerGenerated]
				get
				{
					return _003COriginal_003Ek__BackingField;
				}
				[CompilerGenerated]
				private set
				{
					_003COriginal_003Ek__BackingField = value;
				}
			}

			public Project Project
			{
				get
				{
					return Original.Project;
				}
			}

			public int SlotsCount
			{
				get
				{
					return Original.SlotsCount;
				}
			}

			public int ActiveSlotIndex
			{
				get
				{
					return Original.ActiveSlotIndex;
				}
				set
				{
					if (Original.ActiveSlotIndex != value)
					{
						Original.ActiveSlotIndex = value;
						listener.SetActiveSlotIndex(value);
					}
				}
			}

			public ListenedInventory(IInventoryListener listener, IInventory original)
			{
				this.listener = listener;
				Original = original;
			}

			public void AddSlotItems(int slotIndex, int value, int count)
			{
				Original.AddSlotItems(slotIndex, value, count);
				listener.AddSlotItems(slotIndex, value, count);
			}

			public void DropAllItems(Vector3 position)
			{
				Original.DropAllItems(position);
				listener.DropAllItems(position);
			}

			public int GetSlotCapacity(int slotIndex, int value)
			{
				return Original.GetSlotCapacity(slotIndex, value);
			}

			public int GetSlotCount(int slotIndex)
			{
				return Original.GetSlotCount(slotIndex);
			}

			public int GetSlotProcessCapacity(int slotIndex, int value)
			{
				return Original.GetSlotProcessCapacity(slotIndex, value);
			}

			public int GetSlotValue(int slotIndex)
			{
				return Original.GetSlotValue(slotIndex);
			}

			public void ProcessSlotItems(int slotIndex, int value, int count, int processCount, out int processedValue, out int processedCount)
			{
				Original.ProcessSlotItems(slotIndex, value, count, processCount, ref processedValue, ref processedCount);
				listener.ProcessSlotItems(slotIndex, value, count, processCount);
			}

			public int RemoveSlotItems(int slotIndex, int count)
			{
				int result = Original.RemoveSlotItems(slotIndex, count);
				listener.RemoveSlotItems(slotIndex, count);
				return result;
			}
		}

		private class CreativeInventoryData
		{
			public int activeSlotIndex;

			public int[] lastInventoryCounts = new int[6];

			public int[] lastInventoryValues = new int[6];

			public IInventoryListener listener;

			public CreativeInventoryData(IInventoryListener creativeListener)
			{
				listener = creativeListener;
			}
		}

		private SubsystemGameInfo m_subsystemGameInfo;

		private SubsystemTime m_subsystemTime;

		private SubsystemAudio m_subsystemAudio;

		private SubsystemPickables m_subsystemPickables;

		private SubsystemTerrain m_subsystemTerrain;

		private double m_lastActionTime;

		private bool m_speedOrderBlocked;

		private Nullable<Vector3> m_aimDirection;

		private bool m_isAimBlocked;

		private bool m_isDigBlocked;

		private IPlayerEventListener listener;

		private CreativeInventoryData creativeInventoryData;

		public ComponentPlayer Player;

		public IInventory OriginalInventory
		{
			get
			{
				ListenedInventory listenedInventory = Player.ComponentMiner.Inventory as ListenedInventory;
				if (listenedInventory != null)
				{
					return listenedInventory.Original;
				}
				return Player.ComponentMiner.Inventory;
			}
		}

		public PlayerSlave(Project project, ComponentPlayer player, IPlayerEventListener listener, IInventoryListener inventoryListener)
		{
			m_subsystemGameInfo = project.FindSubsystem<SubsystemGameInfo>(true);
			m_subsystemTime = project.FindSubsystem<SubsystemTime>(true);
			m_subsystemAudio = project.FindSubsystem<SubsystemAudio>(true);
			m_subsystemPickables = project.FindSubsystem<SubsystemPickables>(true);
			m_subsystemTerrain = project.FindSubsystem<SubsystemTerrain>(true);
			SubsystemUpdate subsystemUpdate = project.FindSubsystem<SubsystemUpdate>();
			subsystemUpdate.RemoveUpdateable(player);
			subsystemUpdate.RemoveUpdateable(player.ComponentInput);
			Player = player;
			this.listener = listener;
			if (player.ComponentMiner.Inventory is ComponentCreativeInventory)
			{
				creativeInventoryData = new CreativeInventoryData(inventoryListener);
			}
			else
			{
				ReflectionUtils.SetProperty((object)player.ComponentMiner, "Inventory", (object)new ListenedInventory(inventoryListener, player.ComponentMiner.Inventory));
			}
		}

		public static implicit operator ComponentPlayer(PlayerSlave slave)
		{
			return slave.Player;
		}

		public void ServerUpdate(float dt)
		{
			if (creativeInventoryData != null)
			{
				IInventory inventory = Player.ComponentMiner.Inventory;
				for (int i = 0; i < 6; i++)
				{
					int slotValue = inventory.GetSlotValue(i);
					if (slotValue != creativeInventoryData.lastInventoryValues[i])
					{
						int num = creativeInventoryData.lastInventoryCounts[i];
						if (num > 0)
						{
							creativeInventoryData.listener.RemoveSlotItems(i, num);
						}
						num = inventory.GetSlotCount(i);
						creativeInventoryData.listener.AddSlotItems(i, slotValue, num);
						creativeInventoryData.lastInventoryCounts[i] = num;
						creativeInventoryData.lastInventoryValues[i] = slotValue;
					}
				}
				if (inventory.ActiveSlotIndex != creativeInventoryData.activeSlotIndex)
				{
					creativeInventoryData.listener.SetActiveSlotIndex(inventory.ActiveSlotIndex);
					creativeInventoryData.activeSlotIndex = inventory.ActiveSlotIndex;
				}
			}
			Player.ComponentInput.Update(dt);
			PlayerInput playerInput = Player.ComponentInput.PlayerInput;
			if (Player.ComponentInput.IsControlledByTouch && m_aimDirection.HasValue)
			{
				playerInput.Look = Vector2.Zero;
			}
			if (Player.ComponentMiner.Inventory != null)
			{
				Player.ComponentMiner.Inventory.ActiveSlotIndex = MathUtils.Clamp(Player.ComponentMiner.Inventory.ActiveSlotIndex + playerInput.ScrollInventory, 0, 5);
				if (playerInput.SelectInventorySlot.HasValue)
				{
					Player.ComponentMiner.Inventory.ActiveSlotIndex = MathUtils.Clamp(playerInput.SelectInventorySlot.Value, 0, 5);
				}
			}
			ComponentSteedBehavior componentSteedBehavior = null;
			ComponentBoat componentBoat = null;
			ComponentMount mount = Player.ComponentRider.Mount;
			if (mount != null)
			{
				componentSteedBehavior = mount.Entity.FindComponent<ComponentSteedBehavior>();
				componentBoat = mount.Entity.FindComponent<ComponentBoat>();
			}
			if (componentSteedBehavior != null)
			{
				if (playerInput.Move.Z > 0.5f && !m_speedOrderBlocked)
				{
					if (Player.PlayerData.PlayerClass == PlayerClass.Male)
					{
						m_subsystemAudio.PlayRandomSound("Audio/Creatures/MaleYellFast", 0.75f, 0f, Player.ComponentBody.Position, 2f, false);
					}
					else
					{
						m_subsystemAudio.PlayRandomSound("Audio/Creatures/FemaleYellFast", 0.75f, 0f, Player.ComponentBody.Position, 2f, false);
					}
					componentSteedBehavior.SpeedOrder = 1;
					m_speedOrderBlocked = true;
				}
				else if (playerInput.Move.Z < -0.5f && !m_speedOrderBlocked)
				{
					if (Player.PlayerData.PlayerClass == PlayerClass.Male)
					{
						m_subsystemAudio.PlayRandomSound("Audio/Creatures/MaleYellSlow", 0.75f, 0f, Player.ComponentBody.Position, 2f, false);
					}
					else
					{
						m_subsystemAudio.PlayRandomSound("Audio/Creatures/FemaleYellSlow", 0.75f, 0f, Player.ComponentBody.Position, 2f, false);
					}
					componentSteedBehavior.SpeedOrder = -1;
					m_speedOrderBlocked = true;
				}
				else if (MathUtils.Abs(playerInput.Move.Z) <= 0.25f)
				{
					m_speedOrderBlocked = false;
				}
				componentSteedBehavior.TurnOrder = playerInput.Move.X;
				componentSteedBehavior.JumpOrder = (playerInput.Jump ? 1 : 0);
				Player.ComponentLocomotion.LookOrder = new Vector2(playerInput.Look.X, 0f);
			}
			else if (componentBoat != null)
			{
				componentBoat.TurnOrder = playerInput.Move.X;
				componentBoat.MoveOrder = playerInput.Move.Z;
				Player.ComponentLocomotion.LookOrder = new Vector2(playerInput.Look.X, 0f);
				Player.ComponentCreatureModel.RowLeftOrder = playerInput.Move.X < -0.2f || playerInput.Move.Z > 0.2f;
				Player.ComponentCreatureModel.RowRightOrder = playerInput.Move.X > 0.2f || playerInput.Move.Z > 0.2f;
			}
			else
			{
				Player.ComponentLocomotion.WalkOrder = (Player.ComponentBody.IsSneaking ? (0.66f * new Vector2(playerInput.SneakMove.X, playerInput.SneakMove.Z)) : new Vector2(playerInput.Move.X, playerInput.Move.Z));
				Player.ComponentLocomotion.FlyOrder = new Vector3(0f, playerInput.Move.Y, 0f);
				Player.ComponentLocomotion.TurnOrder = playerInput.Look * new Vector2(1f, 0f);
				Player.ComponentLocomotion.JumpOrder = MathUtils.Max(playerInput.Jump ? 1 : 0, Player.ComponentLocomotion.JumpOrder);
			}
			Player.ComponentLocomotion.LookOrder += playerInput.Look * (SettingsManager.FlipVerticalAxis ? new Vector2(0f, -1f) : new Vector2(0f, 1f));
			int num2 = Terrain.ExtractContents(Player.ComponentMiner.ActiveBlockValue);
			Block block = BlocksManager.Blocks[num2];
			bool flag = false;
			bool hasValue = playerInput.Interact.HasValue;
			if (playerInput.Interact.HasValue && !flag && m_subsystemTime.GameTime - m_lastActionTime > 0.33000001311302185)
			{
				Vector3 viewPosition = Player.View.ActiveCamera.ViewPosition;
				Vector3 vector = Vector3.Normalize(Player.View.ActiveCamera.ScreenToWorld(new Vector3(playerInput.Interact.Value, 1f), Matrix.Identity) - viewPosition);
				if (!Player.ComponentMiner.Use(viewPosition, vector))
				{
					Nullable<BodyRaycastResult> bodyRaycastResult = Player.ComponentMiner.PickBody(viewPosition, vector);
					Nullable<TerrainRaycastResult> terrainRaycastResult = Player.ComponentMiner.PickTerrainForInteraction(viewPosition, vector);
					if (terrainRaycastResult.HasValue && (!bodyRaycastResult.HasValue || terrainRaycastResult.Value.Distance < bodyRaycastResult.Value.Distance))
					{
						if (!Player.ComponentMiner.Interact(terrainRaycastResult.Value))
						{
							if (Player.ComponentMiner.Place(terrainRaycastResult.Value))
							{
								listener.OnPlace(terrainRaycastResult.Value);
								m_subsystemTerrain.TerrainUpdater.RequestSynchronousUpdate();
								flag = true;
								m_isAimBlocked = true;
							}
						}
						else
						{
							listener.OnInteract(terrainRaycastResult.Value);
							m_subsystemTerrain.TerrainUpdater.RequestSynchronousUpdate();
							flag = true;
							m_isAimBlocked = true;
						}
					}
				}
				else
				{
					listener.OnUse(viewPosition, vector);
					m_subsystemTerrain.TerrainUpdater.RequestSynchronousUpdate();
					flag = true;
					m_isAimBlocked = true;
				}
			}
			float num3 = ((m_subsystemGameInfo.WorldSettings.GameMode == GameMode.Creative) ? 0.1f : 1.4f);
			Vector3 viewPosition2 = Player.View.ActiveCamera.ViewPosition;
			if (playerInput.Aim.HasValue && block.IsAimable && m_subsystemTime.GameTime - m_lastActionTime > (double)num3)
			{
				if (!m_isAimBlocked)
				{
					Vector2 value = playerInput.Aim.Value;
					Vector3 vector2 = Player.View.ActiveCamera.ScreenToWorld(new Vector3(value, 1f), Matrix.Identity);
					Point2 size = Window.Size;
					if (playerInput.Aim.Value.X >= (float)size.X * 0.1f && playerInput.Aim.Value.X < (float)size.X * 0.9f && playerInput.Aim.Value.Y >= (float)size.Y * 0.1f && playerInput.Aim.Value.Y < (float)size.Y * 0.9f)
					{
						m_aimDirection = Vector3.Normalize(vector2 - viewPosition2);
						if (Player.ComponentMiner.Aim(viewPosition2, m_aimDirection.Value, AimState.InProgress))
						{
							Player.ComponentMiner.Aim(viewPosition2, m_aimDirection.Value, AimState.Cancelled);
							m_aimDirection = null;
							m_isAimBlocked = true;
						}
					}
					else if (m_aimDirection.HasValue)
					{
						Player.ComponentMiner.Aim(viewPosition2, m_aimDirection.Value, AimState.Cancelled);
						m_aimDirection = null;
						m_isAimBlocked = true;
					}
				}
			}
			else
			{
				m_isAimBlocked = false;
				if (m_aimDirection.HasValue)
				{
					Player.ComponentMiner.Aim(viewPosition2, m_aimDirection.Value, AimState.Completed);
					m_aimDirection = null;
					m_lastActionTime = m_subsystemTime.GameTime;
				}
			}
			flag |= m_aimDirection.HasValue;
			if (playerInput.Hit.HasValue && !flag && m_subsystemTime.GameTime - m_lastActionTime > 0.33000001311302185)
			{
				Vector3 viewPosition3 = Player.View.ActiveCamera.ViewPosition;
				Vector3 vector3 = Vector3.Normalize(Player.View.ActiveCamera.ScreenToWorld(new Vector3(playerInput.Hit.Value, 1f), Matrix.Identity) - viewPosition3);
				Nullable<TerrainRaycastResult> terrainRaycastResult2 = Player.ComponentMiner.PickTerrainForInteraction(viewPosition3, vector3);
				Nullable<BodyRaycastResult> bodyRaycastResult2 = Player.ComponentMiner.PickBody(viewPosition3, vector3);
				if (bodyRaycastResult2.HasValue && (!terrainRaycastResult2.HasValue || terrainRaycastResult2.Value.Distance > bodyRaycastResult2.Value.Distance))
				{
					flag = true;
					m_isDigBlocked = true;
					if (Vector3.Distance(viewPosition3 + vector3 * bodyRaycastResult2.Value.Distance, Player.ComponentCreatureModel.EyePosition) <= 2f)
					{
						Player.ComponentMiner.Hit(bodyRaycastResult2.Value.ComponentBody, vector3);
						listener.OnHit(bodyRaycastResult2.Value.ComponentBody, vector3);
					}
				}
			}
			if (playerInput.Dig.HasValue && !flag && !m_isDigBlocked && m_subsystemTime.GameTime - m_lastActionTime > 0.33000001311302185)
			{
				Vector3 viewPosition4 = Player.View.ActiveCamera.ViewPosition;
				Vector3 vector4 = Player.View.ActiveCamera.ScreenToWorld(new Vector3(playerInput.Dig.Value, 1f), Matrix.Identity);
				Nullable<TerrainRaycastResult> terrainRaycastResult3 = Player.ComponentMiner.PickTerrainForDigging(viewPosition4, vector4 - viewPosition4);
				if (terrainRaycastResult3.HasValue && Player.ComponentMiner.Dig(terrainRaycastResult3.Value))
				{
					listener.OnDig(terrainRaycastResult3.Value);
					m_lastActionTime = m_subsystemTime.GameTime;
					m_subsystemTerrain.TerrainUpdater.RequestSynchronousUpdate();
				}
			}
			if (!playerInput.Dig.HasValue)
			{
				m_isDigBlocked = false;
			}
			if (playerInput.Drop && Player.ComponentMiner.Inventory != null)
			{
				IInventory inventory2 = Player.ComponentMiner.Inventory;
				int slotValue2 = inventory2.GetSlotValue(inventory2.ActiveSlotIndex);
				int slotCount = inventory2.GetSlotCount(inventory2.ActiveSlotIndex);
				int num4 = inventory2.RemoveSlotItems(inventory2.ActiveSlotIndex, slotCount);
				if (slotValue2 != 0 && num4 != 0)
				{
					Vector3 position = Player.ComponentBody.Position + new Vector3(0f, Player.ComponentBody.BoxSize.Y * 0.66f, 0f) + 0.25f * Player.ComponentBody.Matrix.Forward;
					Vector3 value2 = 8f * Matrix.CreateFromQuaternion(Player.ComponentCreatureModel.EyeRotation).Forward;
					m_subsystemPickables.AddPickable(slotValue2, num4, position, value2, null);
				}
			}
			if (playerInput.PickBlockType.HasValue && !flag)
			{
				ComponentCreativeInventory componentCreativeInventory = Player.ComponentMiner.Inventory as ComponentCreativeInventory;
				if (componentCreativeInventory != null)
				{
					Vector3 viewPosition5 = Player.View.ActiveCamera.ViewPosition;
					Vector3 vector5 = Player.View.ActiveCamera.ScreenToWorld(new Vector3(playerInput.PickBlockType.Value, 1f), Matrix.Identity);
					Nullable<TerrainRaycastResult> terrainRaycastResult4 = Player.ComponentMiner.PickTerrainForDigging(viewPosition5, vector5 - viewPosition5);
					if (terrainRaycastResult4.HasValue)
					{
						int value3 = terrainRaycastResult4.Value.Value;
						value3 = Terrain.ReplaceLight(value3, 0);
						int num5 = Terrain.ExtractContents(value3);
						Block block2 = BlocksManager.Blocks[num5];
						int num6 = 0;
						IEnumerable<int> creativeValues = block2.GetCreativeValues();
						if (Enumerable.Contains(block2.GetCreativeValues(), value3))
						{
							num6 = value3;
						}
						if (num6 == 0 && !block2.IsNonDuplicable)
						{
							List<BlockDropValue> list = new List<BlockDropValue>();
							bool showDebris;
							block2.GetDropValues(m_subsystemTerrain, value3, 0, int.MaxValue, list, out showDebris);
							if (list.Count > 0 && list[0].Count > 0)
							{
								num6 = list[0].Value;
							}
						}
						if (num6 == 0)
						{
							num6 = Enumerable.FirstOrDefault(creativeValues);
						}
						if (num6 != 0)
						{
							int num7 = -1;
							for (int j = 0; j < 6; j++)
							{
								if (componentCreativeInventory.GetSlotCount(j) > 0 && componentCreativeInventory.GetSlotValue(j) == num6)
								{
									num7 = j;
									break;
								}
							}
							if (num7 < 0)
							{
								for (int k = 0; k < 6; k++)
								{
									if (componentCreativeInventory.GetSlotCount(k) == 0 || componentCreativeInventory.GetSlotValue(k) == 0)
									{
										num7 = k;
										break;
									}
								}
							}
							if (num7 < 0)
							{
								num7 = componentCreativeInventory.ActiveSlotIndex;
							}
							componentCreativeInventory.RemoveSlotItems(num7, int.MaxValue);
							componentCreativeInventory.AddSlotItems(num7, num6, 1);
							componentCreativeInventory.ActiveSlotIndex = num7;
							Player.ComponentGui.DisplaySmallMessage(block2.GetDisplayName(m_subsystemTerrain, value3), false, false);
							m_subsystemAudio.PlaySound("Audio/UI/ButtonClick", 1f, 0f, 0f, 0f);
						}
					}
				}
			}
			ReflectionUtils.SetProperty((object)Player, "HighlightRaycastResult", (object)Player.ComponentMiner.PickTerrainForDigging(Player.View.ActiveCamera.ViewPosition, Player.View.ActiveCamera.ViewDirection));
		}

		public void ClientUpdate(float dt, RemotePlayerInput playerInput)
		{
			Player.ComponentBody.Position = playerInput.Position;
			Player.ComponentBody.Rotation = playerInput.Rotation;
			Player.ComponentBody.Velocity = playerInput.Velocity;
			Player.ComponentBody.IsSneaking = playerInput.IsSneaking;
			ReflectionUtils.SetField((object)Player.ComponentLocomotion, "m_lookAngles", (object)playerInput.LookAngles);
			Player.ComponentBody.IsGravityEnabled = !playerInput.IsCreativeFlying;
			Player.ComponentLocomotion.IsCreativeFlyEnabled = playerInput.IsCreativeFlying;
			ReflectionUtils.SetProperty((object)Player.ComponentHealth, "Health", (object)playerInput.Health);
		}
	}
}
